class Hash
  rdl_nowrap

  type_params [:k, :v], :all?

  type 'self.[]', '(Array<Array<u>>) -> Hash<u, u>'

  type :[], '(k) -> v'
  type :[]=, '(k, v) -> v'
  type :store, '(k,v) -> v'

  # type :assoc, '(k) -> [k, v]' # TODO
  type :assoc, '(k) -> Array<k or v>'
  type :clear, '() -> Hash<k,v>'
  type :compare_by_identity, '() -> Hash<k,v>'
  type :compare_by_identity?,  '() -> %bool'
  type :default, '(?k) -> v'
  type :default, '(k) {(k) -> v} -> v'
  type :default=, '(v) -> v'

  # TODO: check on default_proc
  #type :default_proc, '() -> (Hash<k,v>,k) -> v'
  #type :default_proc=, '((Hash<k,v>,k) -> v) -> (Hash<k,v>,k) -> v'

  type :delete, '(k) -> v'
  type :delete, '(k) { (k) -> u } -> u or v'
  type :delete_if, '() { (k,v) -> %bool } -> Hash<k,v>'
  type :delete_if, '() -> Enumerator<[k, v]>'
  type :each, '() { (k,v) -> %any } -> Hash<k,v>'
  type :each, '() -> Enumerator<[k, v]>'
  type :each_pair, '() { (k,v) -> %any } -> Hash<k,v>'
  type :each_pair, '() -> Enumerator<[k, v]>'
  type :each_key, '() { (k) -> %any } -> Hash<k,v>'
  type :each_key, '() -> Enumerator<[k, v]>'
  type :each_value, '() { (v) -> %any } -> Hash<k,v>'
  type :each_value, '() -> Enumerator<[k, v]>'
  type :empty?, '() -> %bool'
  type :fetch, '(k) -> v'
  type :fetch, '(k,u) -> u or v'
  type :fetch, '(k) { (k) -> u } -> u or v'
  type :member?, '(t) -> %bool'
  type :has_key?, '(t) -> %bool'
  type :key?, '(t) -> %bool'
  type :has_value?, '(t) -> %bool'
  type :value?, '(t) -> %bool'
  type :to_s, '() -> String'
  type :inspect, '() -> String'
  type :invert, '() -> Hash<v,k>'
  type :keep_if, '() { (k,v) -> %bool } -> Hash<k,v>'
  type :keep_if, '() -> Enumerator<[k, v]>'
  type :key, '(t) -> k'
  type :keys, '() -> Array<k>'
  type :length, '() -> Fixnum'
  type :size, '() -> Fixnum'
  type :merge, '(Hash<a,b>) -> Hash<a or k, b or v>'
  type :merge, '(Hash<a,b>) { (k,v,b) -> v or b } -> Hash<a or k, b or v>'
  # type :rassoc, '(k) -> Tuple<k,v>'
  type :rassoc, '(k) -> Array<k or v>'
  type :rehash, '() -> Hash<k,v>'
  type :reject, '() -> Enumerator<[k, v]>'
  type :reject, '() {(k,v) -> %bool} -> Hash<k,v>'
  type :reject!, '() {(k,v) -> %bool} -> Hash<k,v>'
  type :select, '() {(k,v) -> %bool} -> Hash<k,v>'
  type :select!, '() {(k,v) -> %bool} -> Hash<k,v>'
  # type :shift, '() -> Tuple<k,v>'
  type :shift, '() -> Array<k or v>'
  # type :to_a, '() -> Array<Tuple<k,v>>'
  type :to_a, '() -> Array<Array<k or v>>'
  type :to_hash, '() -> Hash<k,v>'
  type :values, '() -> Array<v>'
  type :values_at, '(*k) -> Array<v>'
end
